001 /* 002 * Copyright 2001-2006 Stephen Colebourne 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.joda.time; 017 018 import java.io.Serializable; 019 import java.util.Calendar; 020 import java.util.Date; 021 import java.util.Locale; 022 023 import org.joda.time.base.BasePartial; 024 import org.joda.time.chrono.ISOChronology; 025 import org.joda.time.field.AbstractPartialFieldProperty; 026 import org.joda.time.field.FieldUtils; 027 import org.joda.time.format.ISODateTimeFormat; 028 029 /** 030 * YearMonthDay is an immutable partial supporting the year, monthOfYear 031 * and dayOfMonth fields. 032 * <p> 033 * NOTE: This class only supports the three fields listed above. Thus, you 034 * cannot query the dayOfWeek or centuryOfEra fields for example. 035 * The new <code>LocalDate</code> class removes this restriction. 036 * <p> 037 * Calculations on YearMonthDay are performed using a {@link Chronology}. 038 * This chronology is set to be in the UTC time zone for all calculations. 039 * <p> 040 * Each individual field can be queried in two ways: 041 * <ul> 042 * <li><code>getMonthOfYear()</code> 043 * <li><code>monthOfYear().get()</code> 044 * </ul> 045 * The second technique also provides access to other useful methods on the 046 * field: 047 * <ul> 048 * <li>numeric value - <code>monthOfYear().get()</code> 049 * <li>text value - <code>monthOfYear().getAsText()</code> 050 * <li>short text value - <code>monthOfYear().getAsShortText()</code> 051 * <li>maximum/minimum values - <code>monthOfYear().getMaximumValue()</code> 052 * <li>add/subtract - <code>monthOfYear().addToCopy()</code> 053 * <li>set - <code>monthOfYear().setCopy()</code> 054 * </ul> 055 * <p> 056 * YearMonthDay is thread-safe and immutable, provided that the Chronology is as well. 057 * All standard Chronology classes supplied are thread-safe and immutable. 058 * 059 * @author Stephen Colebourne 060 * @since 1.0 061 * @deprecated Use LocalDate which has a much better internal implementation and 062 * has been available since 1.3 063 */ 064 public final class YearMonthDay 065 extends BasePartial 066 implements ReadablePartial, Serializable { 067 068 /** Serialization version */ 069 private static final long serialVersionUID = 797544782896179L; 070 /** The singleton set of field types */ 071 private static final DateTimeFieldType[] FIELD_TYPES = new DateTimeFieldType[] { 072 DateTimeFieldType.year(), 073 DateTimeFieldType.monthOfYear(), 074 DateTimeFieldType.dayOfMonth(), 075 }; 076 077 /** The index of the year field in the field array */ 078 public static final int YEAR = 0; 079 /** The index of the monthOfYear field in the field array */ 080 public static final int MONTH_OF_YEAR = 1; 081 /** The index of the dayOfMonth field in the field array */ 082 public static final int DAY_OF_MONTH = 2; 083 084 //----------------------------------------------------------------------- 085 /** 086 * Constructs a YearMonthDay from a <code>java.util.Calendar</code> 087 * using exactly the same field values avoiding any time zone effects. 088 * <p> 089 * Each field is queried from the Calendar and assigned to the YearMonthDay. 090 * This is useful if you have been using the Calendar as a local date, 091 * ignoing the zone. 092 * <p> 093 * This factory method ignores the type of the calendar and always 094 * creates a YearMonthDay with ISO chronology. It is expected that you 095 * will only pass in instances of <code>GregorianCalendar</code> however 096 * this is not validated. 097 * 098 * @param calendar the Calendar to extract fields from 099 * @return the created YearMonthDay 100 * @throws IllegalArgumentException if the calendar is null 101 * @throws IllegalArgumentException if the date is invalid for the ISO chronology 102 * @since 1.2 103 */ 104 public static YearMonthDay fromCalendarFields(Calendar calendar) { 105 if (calendar == null) { 106 throw new IllegalArgumentException("The calendar must not be null"); 107 } 108 return new YearMonthDay( 109 calendar.get(Calendar.YEAR), 110 calendar.get(Calendar.MONTH) + 1, 111 calendar.get(Calendar.DAY_OF_MONTH) 112 ); 113 } 114 115 /** 116 * Constructs a YearMonthDay from a <code>java.util.Date</code> 117 * using exactly the same field values avoiding any time zone effects. 118 * <p> 119 * Each field is queried from the Date and assigned to the YearMonthDay. 120 * This is useful if you have been using the Date as a local date, 121 * ignoing the zone. 122 * <p> 123 * This factory method always creates a YearMonthDay with ISO chronology. 124 * 125 * @param date the Date to extract fields from 126 * @return the created YearMonthDay 127 * @throws IllegalArgumentException if the calendar is null 128 * @throws IllegalArgumentException if the date is invalid for the ISO chronology 129 * @since 1.2 130 */ 131 public static YearMonthDay fromDateFields(Date date) { 132 if (date == null) { 133 throw new IllegalArgumentException("The date must not be null"); 134 } 135 return new YearMonthDay( 136 date.getYear() + 1900, 137 date.getMonth() + 1, 138 date.getDate() 139 ); 140 } 141 142 //----------------------------------------------------------------------- 143 /** 144 * Constructs a YearMonthDay with the current date, using ISOChronology in 145 * the default zone to extract the fields. 146 * <p> 147 * The constructor uses the default time zone, resulting in the local time 148 * being initialised. Once the constructor is complete, all further calculations 149 * are performed without reference to a timezone (by switching to UTC). 150 */ 151 public YearMonthDay() { 152 super(); 153 } 154 155 /** 156 * Constructs a YearMonthDay with the current date, using ISOChronology in 157 * the specified zone to extract the fields. 158 * <p> 159 * The constructor uses the specified time zone to obtain the current date. 160 * Once the constructor is complete, all further calculations 161 * are performed without reference to a timezone (by switching to UTC). 162 * 163 * @param zone the zone to use, null means default zone 164 * @since 1.1 165 */ 166 public YearMonthDay(DateTimeZone zone) { 167 super(ISOChronology.getInstance(zone)); 168 } 169 170 /** 171 * Constructs a YearMonthDay with the current date, using the specified chronology 172 * and zone to extract the fields. 173 * <p> 174 * The constructor uses the time zone of the chronology specified. 175 * Once the constructor is complete, all further calculations are performed 176 * without reference to a timezone (by switching to UTC). 177 * 178 * @param chronology the chronology, null means ISOChronology in the default zone 179 */ 180 public YearMonthDay(Chronology chronology) { 181 super(chronology); 182 } 183 184 /** 185 * Constructs a YearMonthDay extracting the partial fields from the specified 186 * milliseconds using the ISOChronology in the default zone. 187 * <p> 188 * The constructor uses the default time zone, resulting in the local time 189 * being initialised. Once the constructor is complete, all further calculations 190 * are performed without reference to a timezone (by switching to UTC). 191 * 192 * @param instant the milliseconds from 1970-01-01T00:00:00Z 193 */ 194 public YearMonthDay(long instant) { 195 super(instant); 196 } 197 198 /** 199 * Constructs a YearMonthDay extracting the partial fields from the specified 200 * milliseconds using the chronology provided. 201 * <p> 202 * The constructor uses the time zone of the chronology specified. 203 * Once the constructor is complete, all further calculations are performed 204 * without reference to a timezone (by switching to UTC). 205 * 206 * @param instant the milliseconds from 1970-01-01T00:00:00Z 207 * @param chronology the chronology, null means ISOChronology in the default zone 208 */ 209 public YearMonthDay(long instant, Chronology chronology) { 210 super(instant, chronology); 211 } 212 213 /** 214 * Constructs a YearMonthDay from an Object that represents a time. 215 * <p> 216 * The recognised object types are defined in 217 * {@link org.joda.time.convert.ConverterManager ConverterManager} and 218 * include ReadableInstant, String, Calendar and Date. 219 * The String formats are described by {@link ISODateTimeFormat#dateOptionalTimeParser()}. 220 * <p> 221 * The chronology used will be derived from the object, defaulting to ISO. 222 * <p> 223 * NOTE: Prior to v1.3 the string format was described by 224 * {@link ISODateTimeFormat#dateTimeParser()}. Time ony strings are now rejected. 225 * 226 * @param instant the datetime object, null means now 227 * @throws IllegalArgumentException if the instant is invalid 228 */ 229 public YearMonthDay(Object instant) { 230 super(instant, null, ISODateTimeFormat.dateOptionalTimeParser()); 231 } 232 233 /** 234 * Constructs a YearMonthDay from an Object that represents a time, using the 235 * specified chronology. 236 * <p> 237 * The recognised object types are defined in 238 * {@link org.joda.time.convert.ConverterManager ConverterManager} and 239 * include ReadableInstant, String, Calendar and Date. 240 * The String formats are described by {@link ISODateTimeFormat#dateOptionalTimeParser()}. 241 * <p> 242 * The constructor uses the time zone of the chronology specified. 243 * Once the constructor is complete, all further calculations are performed 244 * without reference to a timezone (by switching to UTC). 245 * The specified chronology overrides that of the object. 246 * <p> 247 * NOTE: Prior to v1.3 the string format was described by 248 * {@link ISODateTimeFormat#dateTimeParser()}. Time only strings are now rejected. 249 * 250 * @param instant the datetime object, null means now 251 * @param chronology the chronology, null means ISO default 252 * @throws IllegalArgumentException if the instant is invalid 253 */ 254 public YearMonthDay(Object instant, Chronology chronology) { 255 super(instant, DateTimeUtils.getChronology(chronology), ISODateTimeFormat.dateOptionalTimeParser()); 256 } 257 258 /** 259 * Constructs a YearMonthDay with specified time field values 260 * using <code>ISOChronology</code> in the default zone. 261 * <p> 262 * The constructor uses the no time zone initialising the fields as provided. 263 * Once the constructor is complete, all further calculations 264 * are performed without reference to a timezone (by switching to UTC). 265 * 266 * @param year the year 267 * @param monthOfYear the month of the year 268 * @param dayOfMonth the day of the month 269 */ 270 public YearMonthDay(int year, int monthOfYear, int dayOfMonth) { 271 this(year, monthOfYear, dayOfMonth, null); 272 } 273 274 /** 275 * Constructs a YearMonthDay with specified time field values. 276 * <p> 277 * The constructor uses the time zone of the chronology specified. 278 * Once the constructor is complete, all further calculations are performed 279 * without reference to a timezone (by switching to UTC). 280 * 281 * @param year the year 282 * @param monthOfYear the month of the year 283 * @param dayOfMonth the day of the month 284 * @param chronology the chronology, null means ISOChronology in the default zone 285 */ 286 public YearMonthDay(int year, int monthOfYear, int dayOfMonth, Chronology chronology) { 287 super(new int[] {year, monthOfYear, dayOfMonth}, chronology); 288 } 289 290 /** 291 * Constructs a YearMonthDay with chronology from this instance and new values. 292 * 293 * @param partial the partial to base this new instance on 294 * @param values the new set of values 295 */ 296 YearMonthDay(YearMonthDay partial, int[] values) { 297 super(partial, values); 298 } 299 300 /** 301 * Constructs a YearMonthDay with values from this instance and a new chronology. 302 * 303 * @param partial the partial to base this new instance on 304 * @param chrono the new chronology 305 */ 306 YearMonthDay(YearMonthDay partial, Chronology chrono) { 307 super(partial, chrono); 308 } 309 310 //----------------------------------------------------------------------- 311 /** 312 * Gets the number of fields in this partial. 313 * 314 * @return the field count 315 */ 316 public int size() { 317 return 3; 318 } 319 320 /** 321 * Gets the field for a specific index in the chronology specified. 322 * <p> 323 * This method must not use any instance variables. 324 * 325 * @param index the index to retrieve 326 * @param chrono the chronology to use 327 * @return the field 328 */ 329 protected DateTimeField getField(int index, Chronology chrono) { 330 switch (index) { 331 case YEAR: 332 return chrono.year(); 333 case MONTH_OF_YEAR: 334 return chrono.monthOfYear(); 335 case DAY_OF_MONTH: 336 return chrono.dayOfMonth(); 337 default: 338 throw new IndexOutOfBoundsException("Invalid index: " + index); 339 } 340 } 341 342 /** 343 * Gets the field type at the specified index. 344 * 345 * @param index the index to retrieve 346 * @return the field at the specified index 347 * @throws IndexOutOfBoundsException if the index is invalid 348 */ 349 public DateTimeFieldType getFieldType(int index) { 350 return FIELD_TYPES[index]; 351 } 352 353 /** 354 * Gets an array of the field type of each of the fields that this partial supports. 355 * <p> 356 * The fields are returned largest to smallest, Year, Month, Day 357 * 358 * @return the array of field types (cloned), largest to smallest 359 */ 360 public DateTimeFieldType[] getFieldTypes() { 361 return (DateTimeFieldType[]) FIELD_TYPES.clone(); 362 } 363 364 //----------------------------------------------------------------------- 365 /** 366 * Returns a copy of this date with the specified chronology. 367 * This instance is immutable and unaffected by this method call. 368 * <p> 369 * This method retains the values of the fields, thus the result will 370 * typically refer to a different instant. 371 * <p> 372 * The time zone of the specified chronology is ignored, as YearMonthDay 373 * operates without a time zone. 374 * 375 * @param newChronology the new chronology, null means ISO 376 * @return a copy of this datetime with a different chronology 377 * @throws IllegalArgumentException if the values are invalid for the new chronology 378 */ 379 public YearMonthDay withChronologyRetainFields(Chronology newChronology) { 380 newChronology = DateTimeUtils.getChronology(newChronology); 381 newChronology = newChronology.withUTC(); 382 if (newChronology == getChronology()) { 383 return this; 384 } else { 385 YearMonthDay newYearMonthDay = new YearMonthDay(this, newChronology); 386 newChronology.validate(newYearMonthDay, getValues()); 387 return newYearMonthDay; 388 } 389 } 390 391 /** 392 * Returns a copy of this date with the specified field set to a new value. 393 * <p> 394 * For example, if the field type is <code>dayOfMonth</code> then the day 395 * would be changed in the returned instance. 396 * <p> 397 * These three lines are equivalent: 398 * <pre> 399 * YearMonthDay updated = ymd.withField(DateTimeFieldType.dayOfMonth(), 6); 400 * YearMonthDay updated = ymd.dayOfMonth().setCopy(6); 401 * YearMonthDay updated = ymd.property(DateTimeFieldType.dayOfMonth()).setCopy(6); 402 * </pre> 403 * 404 * @param fieldType the field type to set, not null 405 * @param value the value to set 406 * @return a copy of this instance with the field set 407 * @throws IllegalArgumentException if the value is null or invalid 408 */ 409 public YearMonthDay withField(DateTimeFieldType fieldType, int value) { 410 int index = indexOfSupported(fieldType); 411 if (value == getValue(index)) { 412 return this; 413 } 414 int[] newValues = getValues(); 415 newValues = getField(index).set(this, index, newValues, value); 416 return new YearMonthDay(this, newValues); 417 } 418 419 /** 420 * Returns a copy of this date with the value of the specified field increased. 421 * <p> 422 * If the addition is zero, then <code>this</code> is returned. 423 * <p> 424 * These three lines are equivalent: 425 * <pre> 426 * YearMonthDay added = ymd.withFieldAdded(DurationFieldType.days(), 6); 427 * YearMonthDay added = ymd.plusDays(6); 428 * YearMonthDay added = ymd.dayOfMonth().addToCopy(6); 429 * </pre> 430 * 431 * @param fieldType the field type to add to, not null 432 * @param amount the amount to add 433 * @return a copy of this instance with the field updated 434 * @throws IllegalArgumentException if the value is null or invalid 435 * @throws ArithmeticException if the new datetime exceeds the capacity 436 */ 437 public YearMonthDay withFieldAdded(DurationFieldType fieldType, int amount) { 438 int index = indexOfSupported(fieldType); 439 if (amount == 0) { 440 return this; 441 } 442 int[] newValues = getValues(); 443 newValues = getField(index).add(this, index, newValues, amount); 444 return new YearMonthDay(this, newValues); 445 } 446 447 /** 448 * Returns a copy of this date with the specified period added. 449 * <p> 450 * If the addition is zero, then <code>this</code> is returned. 451 * Fields in the period that aren't present in the partial are ignored. 452 * <p> 453 * This method is typically used to add multiple copies of complex 454 * period instances. Adding one field is best achieved using methods 455 * like {@link #withFieldAdded(DurationFieldType, int)} 456 * or {@link #plusYears(int)}. 457 * 458 * @param period the period to add to this one, null means zero 459 * @param scalar the amount of times to add, such as -1 to subtract once 460 * @return a copy of this instance with the period added 461 * @throws ArithmeticException if the new datetime exceeds the capacity 462 */ 463 public YearMonthDay withPeriodAdded(ReadablePeriod period, int scalar) { 464 if (period == null || scalar == 0) { 465 return this; 466 } 467 int[] newValues = getValues(); 468 for (int i = 0; i < period.size(); i++) { 469 DurationFieldType fieldType = period.getFieldType(i); 470 int index = indexOf(fieldType); 471 if (index >= 0) { 472 newValues = getField(index).add(this, index, newValues, 473 FieldUtils.safeMultiply(period.getValue(i), scalar)); 474 } 475 } 476 return new YearMonthDay(this, newValues); 477 } 478 479 //----------------------------------------------------------------------- 480 /** 481 * Returns a copy of this date with the specified period added. 482 * <p> 483 * If the amount is zero or null, then <code>this</code> is returned. 484 * <p> 485 * This method is typically used to add complex period instances. 486 * Adding one field is best achieved using methods 487 * like {@link #plusYears(int)}. 488 * 489 * @param period the duration to add to this one, null means zero 490 * @return a copy of this instance with the period added 491 * @throws ArithmeticException if the new datetime exceeds the capacity of a long 492 */ 493 public YearMonthDay plus(ReadablePeriod period) { 494 return withPeriodAdded(period, 1); 495 } 496 497 //----------------------------------------------------------------------- 498 /** 499 * Returns a copy of this date plus the specified number of years. 500 * <p> 501 * This date instance is immutable and unaffected by this method call. 502 * <p> 503 * The following three lines are identical in effect: 504 * <pre> 505 * YearMonthDay added = dt.plusYears(6); 506 * YearMonthDay added = dt.plus(Period.years(6)); 507 * YearMonthDay added = dt.withFieldAdded(DurationFieldType.years(), 6); 508 * </pre> 509 * 510 * @param years the amount of years to add, may be negative 511 * @return the new date plus the increased years 512 * @since 1.1 513 */ 514 public YearMonthDay plusYears(int years) { 515 return withFieldAdded(DurationFieldType.years(), years); 516 } 517 518 /** 519 * Returns a copy of this date plus the specified number of months. 520 * <p> 521 * This date instance is immutable and unaffected by this method call. 522 * <p> 523 * The following three lines are identical in effect: 524 * <pre> 525 * YearMonthDay added = dt.plusMonths(6); 526 * YearMonthDay added = dt.plus(Period.months(6)); 527 * YearMonthDay added = dt.withFieldAdded(DurationFieldType.months(), 6); 528 * </pre> 529 * 530 * @param months the amount of months to add, may be negative 531 * @return the new date plus the increased months 532 * @since 1.1 533 */ 534 public YearMonthDay plusMonths(int months) { 535 return withFieldAdded(DurationFieldType.months(), months); 536 } 537 538 /** 539 * Returns a copy of this date plus the specified number of days. 540 * <p> 541 * This date instance is immutable and unaffected by this method call. 542 * <p> 543 * The following three lines are identical in effect: 544 * <pre> 545 * YearMonthDay added = dt.plusDays(6); 546 * YearMonthDay added = dt.plus(Period.days(6)); 547 * YearMonthDay added = dt.withFieldAdded(DurationFieldType.days(), 6); 548 * </pre> 549 * 550 * @param days the amount of days to add, may be negative 551 * @return the new date plus the increased days 552 * @since 1.1 553 */ 554 public YearMonthDay plusDays(int days) { 555 return withFieldAdded(DurationFieldType.days(), days); 556 } 557 558 //----------------------------------------------------------------------- 559 /** 560 * Returns a copy of this date with the specified period taken away. 561 * <p> 562 * If the amount is zero or null, then <code>this</code> is returned. 563 * <p> 564 * This method is typically used to subtract complex period instances. 565 * Subtracting one field is best achieved using methods 566 * like {@link #minusYears(int)}. 567 * 568 * @param period the period to reduce this instant by 569 * @return a copy of this instance with the period taken away 570 * @throws ArithmeticException if the new datetime exceeds the capacity of a long 571 */ 572 public YearMonthDay minus(ReadablePeriod period) { 573 return withPeriodAdded(period, -1); 574 } 575 576 //----------------------------------------------------------------------- 577 /** 578 * Returns a copy of this date minus the specified number of years. 579 * <p> 580 * This datetime instance is immutable and unaffected by this method call. 581 * <p> 582 * The following three lines are identical in effect: 583 * <pre> 584 * YearMonthDay subtracted = dt.minusYears(6); 585 * YearMonthDay subtracted = dt.minus(Period.years(6)); 586 * YearMonthDay subtracted = dt.withFieldAdded(DurationFieldType.years(), -6); 587 * </pre> 588 * 589 * @param years the amount of years to subtract, may be negative 590 * @return the new datetime minus the increased years 591 * @since 1.1 592 */ 593 public YearMonthDay minusYears(int years) { 594 return withFieldAdded(DurationFieldType.years(), FieldUtils.safeNegate(years)); 595 } 596 597 /** 598 * Returns a copy of this date minus the specified number of months. 599 * <p> 600 * This datetime instance is immutable and unaffected by this method call. 601 * <p> 602 * The following three lines are identical in effect: 603 * <pre> 604 * YearMonthDay subtracted = dt.minusMonths(6); 605 * YearMonthDay subtracted = dt.minus(Period.months(6)); 606 * YearMonthDay subtracted = dt.withFieldAdded(DurationFieldType.months(), -6); 607 * </pre> 608 * 609 * @param months the amount of months to subtract, may be negative 610 * @return the new datetime minus the increased months 611 * @since 1.1 612 */ 613 public YearMonthDay minusMonths(int months) { 614 return withFieldAdded(DurationFieldType.months(), FieldUtils.safeNegate(months)); 615 } 616 617 /** 618 * Returns a copy of this date minus the specified number of days. 619 * <p> 620 * This datetime instance is immutable and unaffected by this method call. 621 * <p> 622 * The following three lines are identical in effect: 623 * <pre> 624 * YearMonthDay subtracted = dt.minusDays(6); 625 * YearMonthDay subtracted = dt.minus(Period.days(6)); 626 * YearMonthDay subtracted = dt.withFieldAdded(DurationFieldType.days(), -6); 627 * </pre> 628 * 629 * @param days the amount of days to subtract, may be negative 630 * @return the new datetime minus the increased days 631 * @since 1.1 632 */ 633 public YearMonthDay minusDays(int days) { 634 return withFieldAdded(DurationFieldType.days(), FieldUtils.safeNegate(days)); 635 } 636 637 //----------------------------------------------------------------------- 638 /** 639 * Gets the property object for the specified type, which contains 640 * many useful methods. 641 * 642 * @param type the field type to get the property for 643 * @return the property object 644 * @throws IllegalArgumentException if the field is null or unsupported 645 */ 646 public Property property(DateTimeFieldType type) { 647 return new Property(this, indexOfSupported(type)); 648 } 649 650 //----------------------------------------------------------------------- 651 /** 652 * Converts this object to a LocalDate with the same date and chronology. 653 * 654 * @return a LocalDate with the same date and chronology 655 * @since 1.3 656 */ 657 public LocalDate toLocalDate() { 658 return new LocalDate(getYear(), getMonthOfYear(), getDayOfMonth(), getChronology()); 659 } 660 661 //----------------------------------------------------------------------- 662 /** 663 * Converts this YearMonthDay to a full datetime at midnight using the 664 * default time zone. 665 * 666 * @return this date as a datetime at midnight 667 */ 668 public DateTime toDateTimeAtMidnight() { 669 return toDateTimeAtMidnight(null); 670 } 671 672 /** 673 * Converts this YearMonthDay to a full datetime at midnight using the 674 * specified time zone. 675 * <p> 676 * This method uses the chronology from this instance plus the time zone 677 * specified. 678 * 679 * @param zone the zone to use, null means default 680 * @return this date as a datetime at midnight 681 */ 682 public DateTime toDateTimeAtMidnight(DateTimeZone zone) { 683 Chronology chrono = getChronology().withZone(zone); 684 return new DateTime(getYear(), getMonthOfYear(), getDayOfMonth(), 0, 0, 0, 0, chrono); 685 } 686 687 //----------------------------------------------------------------------- 688 /** 689 * Converts this partial to a full datetime using the default time zone 690 * setting the date fields from this instance and the time fields from 691 * the current time. 692 * 693 * @return this date as a datetime with the time as the current time 694 */ 695 public DateTime toDateTimeAtCurrentTime() { 696 return toDateTimeAtCurrentTime(null); 697 } 698 699 /** 700 * Converts this partial to a full datetime using the specified time zone 701 * setting the date fields from this instance and the time fields from 702 * the current time. 703 * <p> 704 * This method uses the chronology from this instance plus the time zone 705 * specified. 706 * 707 * @param zone the zone to use, null means default 708 * @return this date as a datetime with the time as the current time 709 */ 710 public DateTime toDateTimeAtCurrentTime(DateTimeZone zone) { 711 Chronology chrono = getChronology().withZone(zone); 712 long instantMillis = DateTimeUtils.currentTimeMillis(); 713 long resolved = chrono.set(this, instantMillis); 714 return new DateTime(resolved, chrono); 715 } 716 717 //----------------------------------------------------------------------- 718 /** 719 * Converts this object to a DateMidnight in the default time zone. 720 * 721 * @return the DateMidnight instance in the default zone 722 */ 723 public DateMidnight toDateMidnight() { 724 return toDateMidnight(null); 725 } 726 727 /** 728 * Converts this object to a DateMidnight. 729 * 730 * @param zone the zone to get the DateMidnight in, null means default 731 * @return the DateMidnight instance 732 */ 733 public DateMidnight toDateMidnight(DateTimeZone zone) { 734 Chronology chrono = getChronology().withZone(zone); 735 return new DateMidnight(getYear(), getMonthOfYear(), getDayOfMonth(), chrono); 736 } 737 738 //----------------------------------------------------------------------- 739 /** 740 * Converts this object to a DateTime using a TimeOfDay to fill in the 741 * missing fields and using the default time zone. 742 * This instance is immutable and unaffected by this method call. 743 * <p> 744 * The resulting chronology is determined by the chronology of this 745 * YearMonthDay plus the time zone. 746 * The chronology of the time is ignored - only the field values are used. 747 * 748 * @param time the time of day to use, null means current time 749 * @return the DateTime instance 750 */ 751 public DateTime toDateTime(TimeOfDay time) { 752 return toDateTime(time, null); 753 } 754 755 /** 756 * Converts this object to a DateTime using a TimeOfDay to fill in the 757 * missing fields. 758 * This instance is immutable and unaffected by this method call. 759 * <p> 760 * The resulting chronology is determined by the chronology of this 761 * YearMonthDay plus the time zone. 762 * The chronology of the time is ignored - only the field values are used. 763 * 764 * @param time the time of day to use, null means current time 765 * @param zone the zone to get the DateTime in, null means default 766 * @return the DateTime instance 767 */ 768 public DateTime toDateTime(TimeOfDay time, DateTimeZone zone) { 769 Chronology chrono = getChronology().withZone(zone); 770 long instant = DateTimeUtils.currentTimeMillis(); 771 instant = chrono.set(this, instant); 772 if (time != null) { 773 instant = chrono.set(time, instant); 774 } 775 return new DateTime(instant, chrono); 776 } 777 778 //----------------------------------------------------------------------- 779 /** 780 * Converts this object to an Interval representing the whole day 781 * in the default time zone. 782 * 783 * @return a interval over the day 784 */ 785 public Interval toInterval() { 786 return toInterval(null); 787 } 788 789 /** 790 * Converts this object to an Interval representing the whole day. 791 * 792 * @param zone the zone to get the Interval in, null means default 793 * @return a interval over the day 794 */ 795 public Interval toInterval(DateTimeZone zone) { 796 zone = DateTimeUtils.getZone(zone); 797 return toDateMidnight(zone).toInterval(); 798 } 799 800 //----------------------------------------------------------------------- 801 /** 802 * Get the year field value. 803 * 804 * @return the year 805 */ 806 public int getYear() { 807 return getValue(YEAR); 808 } 809 810 /** 811 * Get the month of year field value. 812 * 813 * @return the month of year 814 */ 815 public int getMonthOfYear() { 816 return getValue(MONTH_OF_YEAR); 817 } 818 819 /** 820 * Get the day of month field value. 821 * 822 * @return the day of month 823 */ 824 public int getDayOfMonth() { 825 return getValue(DAY_OF_MONTH); 826 } 827 828 //----------------------------------------------------------------------- 829 /** 830 * Returns a copy of this date with the year field updated. 831 * <p> 832 * YearMonthDay is immutable, so there are no set methods. 833 * Instead, this method returns a new instance with the value of 834 * year changed. 835 * 836 * @param year the year to set 837 * @return a copy of this object with the field set 838 * @throws IllegalArgumentException if the value is invalid 839 * @since 1.3 840 */ 841 public YearMonthDay withYear(int year) { 842 int[] newValues = getValues(); 843 newValues = getChronology().year().set(this, YEAR, newValues, year); 844 return new YearMonthDay(this, newValues); 845 } 846 847 /** 848 * Returns a copy of this date with the month of year field updated. 849 * <p> 850 * YearMonthDay is immutable, so there are no set methods. 851 * Instead, this method returns a new instance with the value of 852 * month of year changed. 853 * 854 * @param monthOfYear the month of year to set 855 * @return a copy of this object with the field set 856 * @throws IllegalArgumentException if the value is invalid 857 * @since 1.3 858 */ 859 public YearMonthDay withMonthOfYear(int monthOfYear) { 860 int[] newValues = getValues(); 861 newValues = getChronology().monthOfYear().set(this, MONTH_OF_YEAR, newValues, monthOfYear); 862 return new YearMonthDay(this, newValues); 863 } 864 865 /** 866 * Returns a copy of this date with the day of month field updated. 867 * <p> 868 * YearMonthDay is immutable, so there are no set methods. 869 * Instead, this method returns a new instance with the value of 870 * day of month changed. 871 * 872 * @param dayOfMonth the day of month to set 873 * @return a copy of this object with the field set 874 * @throws IllegalArgumentException if the value is invalid 875 * @since 1.3 876 */ 877 public YearMonthDay withDayOfMonth(int dayOfMonth) { 878 int[] newValues = getValues(); 879 newValues = getChronology().dayOfMonth().set(this, DAY_OF_MONTH, newValues, dayOfMonth); 880 return new YearMonthDay(this, newValues); 881 } 882 883 //----------------------------------------------------------------------- 884 /** 885 * Get the year field property which provides access to advanced functionality. 886 * 887 * @return the year property 888 */ 889 public Property year() { 890 return new Property(this, YEAR); 891 } 892 893 /** 894 * Get the month of year field property which provides access to advanced functionality. 895 * 896 * @return the month of year property 897 */ 898 public Property monthOfYear() { 899 return new Property(this, MONTH_OF_YEAR); 900 } 901 902 /** 903 * Get the day of month field property which provides access to advanced functionality. 904 * 905 * @return the day of month property 906 */ 907 public Property dayOfMonth() { 908 return new Property(this, DAY_OF_MONTH); 909 } 910 911 //----------------------------------------------------------------------- 912 /** 913 * Output the date in the ISO8601 format YYYY-MM-DD. 914 * 915 * @return ISO8601 formatted string 916 */ 917 public String toString() { 918 return ISODateTimeFormat.yearMonthDay().print(this); 919 } 920 921 //----------------------------------------------------------------------- 922 /** 923 * The property class for <code>YearMonthDay</code>. 924 * <p> 925 * This class binds a <code>YearMonthDay</code> to a <code>DateTimeField</code>. 926 * 927 * @author Stephen Colebourne 928 * @since 1.0 929 * @deprecated Use LocalDate which has a much better internal implementation 930 */ 931 public static class Property extends AbstractPartialFieldProperty implements Serializable { 932 933 /** Serialization version */ 934 private static final long serialVersionUID = 5727734012190224363L; 935 936 /** The partial */ 937 private final YearMonthDay iYearMonthDay; 938 /** The field index */ 939 private final int iFieldIndex; 940 941 /** 942 * Constructs a property. 943 * 944 * @param partial the partial instance 945 * @param fieldIndex the index in the partial 946 */ 947 Property(YearMonthDay partial, int fieldIndex) { 948 super(); 949 iYearMonthDay = partial; 950 iFieldIndex = fieldIndex; 951 } 952 953 /** 954 * Gets the field that this property uses. 955 * 956 * @return the field 957 */ 958 public DateTimeField getField() { 959 return iYearMonthDay.getField(iFieldIndex); 960 } 961 962 /** 963 * Gets the partial that this property belongs to. 964 * 965 * @return the partial 966 */ 967 protected ReadablePartial getReadablePartial() { 968 return iYearMonthDay; 969 } 970 971 /** 972 * Gets the partial that this property belongs to. 973 * 974 * @return the partial 975 */ 976 public YearMonthDay getYearMonthDay() { 977 return iYearMonthDay; 978 } 979 980 /** 981 * Gets the value of this field. 982 * 983 * @return the field value 984 */ 985 public int get() { 986 return iYearMonthDay.getValue(iFieldIndex); 987 } 988 989 //----------------------------------------------------------------------- 990 /** 991 * Adds to the value of this field in a copy of this YearMonthDay. 992 * <p> 993 * The value will be added to this field. If the value is too large to be 994 * added solely to this field then it will affect larger fields. 995 * Smaller fields are unaffected. 996 * <p> 997 * If the result would be too large, beyond the maximum year, then an 998 * IllegalArgumentException is thrown. 999 * <p> 1000 * The YearMonthDay attached to this property is unchanged by this call. 1001 * Instead, a new instance is returned. 1002 * 1003 * @param valueToAdd the value to add to the field in the copy 1004 * @return a copy of the YearMonthDay with the field value changed 1005 * @throws IllegalArgumentException if the value isn't valid 1006 */ 1007 public YearMonthDay addToCopy(int valueToAdd) { 1008 int[] newValues = iYearMonthDay.getValues(); 1009 newValues = getField().add(iYearMonthDay, iFieldIndex, newValues, valueToAdd); 1010 return new YearMonthDay(iYearMonthDay, newValues); 1011 } 1012 1013 /** 1014 * Adds to the value of this field in a copy of this YearMonthDay wrapping 1015 * within this field if the maximum value is reached. 1016 * <p> 1017 * The value will be added to this field. If the value is too large to be 1018 * added solely to this field then it wraps within this field. 1019 * Other fields are unaffected. 1020 * <p> 1021 * For example, 1022 * <code>2004-12-20</code> addWrapField one month returns <code>2004-01-20</code>. 1023 * <p> 1024 * The YearMonthDay attached to this property is unchanged by this call. 1025 * Instead, a new instance is returned. 1026 * 1027 * @param valueToAdd the value to add to the field in the copy 1028 * @return a copy of the YearMonthDay with the field value changed 1029 * @throws IllegalArgumentException if the value isn't valid 1030 */ 1031 public YearMonthDay addWrapFieldToCopy(int valueToAdd) { 1032 int[] newValues = iYearMonthDay.getValues(); 1033 newValues = getField().addWrapField(iYearMonthDay, iFieldIndex, newValues, valueToAdd); 1034 return new YearMonthDay(iYearMonthDay, newValues); 1035 } 1036 1037 //----------------------------------------------------------------------- 1038 /** 1039 * Sets this field in a copy of the YearMonthDay. 1040 * <p> 1041 * The YearMonthDay attached to this property is unchanged by this call. 1042 * Instead, a new instance is returned. 1043 * 1044 * @param value the value to set the field in the copy to 1045 * @return a copy of the YearMonthDay with the field value changed 1046 * @throws IllegalArgumentException if the value isn't valid 1047 */ 1048 public YearMonthDay setCopy(int value) { 1049 int[] newValues = iYearMonthDay.getValues(); 1050 newValues = getField().set(iYearMonthDay, iFieldIndex, newValues, value); 1051 return new YearMonthDay(iYearMonthDay, newValues); 1052 } 1053 1054 /** 1055 * Sets this field in a copy of the YearMonthDay to a parsed text value. 1056 * <p> 1057 * The YearMonthDay attached to this property is unchanged by this call. 1058 * Instead, a new instance is returned. 1059 * 1060 * @param text the text value to set 1061 * @param locale optional locale to use for selecting a text symbol 1062 * @return a copy of the YearMonthDay with the field value changed 1063 * @throws IllegalArgumentException if the text value isn't valid 1064 */ 1065 public YearMonthDay setCopy(String text, Locale locale) { 1066 int[] newValues = iYearMonthDay.getValues(); 1067 newValues = getField().set(iYearMonthDay, iFieldIndex, newValues, text, locale); 1068 return new YearMonthDay(iYearMonthDay, newValues); 1069 } 1070 1071 /** 1072 * Sets this field in a copy of the YearMonthDay to a parsed text value. 1073 * <p> 1074 * The YearMonthDay attached to this property is unchanged by this call. 1075 * Instead, a new instance is returned. 1076 * 1077 * @param text the text value to set 1078 * @return a copy of the YearMonthDay with the field value changed 1079 * @throws IllegalArgumentException if the text value isn't valid 1080 */ 1081 public YearMonthDay setCopy(String text) { 1082 return setCopy(text, null); 1083 } 1084 1085 //----------------------------------------------------------------------- 1086 /** 1087 * Returns a new YearMonthDay with this field set to the maximum value 1088 * for this field. 1089 * <p> 1090 * This operation is useful for obtaining a DateTime on the last day 1091 * of the month, as month lengths vary. 1092 * <pre> 1093 * YearMonthDay lastDayOfMonth = dt.dayOfMonth().withMaximumValue(); 1094 * </pre> 1095 * <p> 1096 * The YearMonthDay attached to this property is unchanged by this call. 1097 * 1098 * @return a copy of the YearMonthDay with this field set to its maximum 1099 * @since 1.2 1100 */ 1101 public YearMonthDay withMaximumValue() { 1102 return setCopy(getMaximumValue()); 1103 } 1104 1105 /** 1106 * Returns a new YearMonthDay with this field set to the minimum value 1107 * for this field. 1108 * <p> 1109 * The YearMonthDay attached to this property is unchanged by this call. 1110 * 1111 * @return a copy of the YearMonthDay with this field set to its minimum 1112 * @since 1.2 1113 */ 1114 public YearMonthDay withMinimumValue() { 1115 return setCopy(getMinimumValue()); 1116 } 1117 } 1118 1119 }